package com.nineclock.auth.aop;

import com.nineclock.auth.entity.IntegrationAuthenticationEntity;
import com.nineclock.auth.entity.NcOauthTokenDTO;
import com.nineclock.auth.threadlocal.IntegrationAuthenticationHolder;
import com.nineclock.auth.threadlocal.UserHolder;
import com.nineclock.common.entity.Result;
import com.nineclock.common.entity.UserInfo;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * @author 黑马程序员
 * @Company http://www.ithiema.com
 * @Version 1.0
 */
@Slf4j
@Aspect //配置切面
@Component //创建通知对象
public class AuthTokenAspect {

    @Autowired
    HttpServletRequest request;


    private static final String AUTH_TYPE_PARM_NAME = "auth_type";
    /**
     * 环绕增强
     *  在环绕增强中必须 调用原始方法
     * ProceedingJoinPoint joinPoint: 连接点， 通过此连接点可以 调用原始方法
     *
     *
     * postAccessToken 对此方法进行环绕增强
     * @return
     */
    @Around("execution(* org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            //获取request对象
//            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

            //前置增强内容
            IntegrationAuthenticationEntity entity = new IntegrationAuthenticationEntity();

            //从请求域中获取认证类型
            String authType = request.getParameter(AUTH_TYPE_PARM_NAME);
            entity.setAuthType(authType);
            //从请求域中获取 所有的请求参数
            Map<String, String[]> parameterMap = request.getParameterMap();
            entity.setAuthParameters(parameterMap);

            //存储到当前线程中
            IntegrationAuthenticationHolder.set(entity);

            //执行原始方法(postAccessToken)， 获取返回值
            Object resultObj = joinPoint.proceed();
            //后置增强
            if(resultObj != null){
                ResponseEntity<OAuth2AccessToken> responseEntity = (ResponseEntity<OAuth2AccessToken>) resultObj;
                //认证后获取 的token信息
                OAuth2AccessToken body = responseEntity.getBody();
                //从线程中获取userInfo信息
                UserInfo userInfo = UserHolder.get();
                //创建NcOauthTokenDTO
                NcOauthTokenDTO ncOauthTokenDTO = new NcOauthTokenDTO(body, userInfo);
                Result result = null;
                if(responseEntity.getStatusCode().is2xxSuccessful()){
                    result = Result.success(ncOauthTokenDTO);
                }else{
                    result = Result.errorCodeMessage(responseEntity.getStatusCodeValue(), "获取令牌失败");
                }
                //返回统一类型的结果
                return ResponseEntity.ok(result);
            }
            return  resultObj;
        } finally {
            //移除线程中的对象
            IntegrationAuthenticationHolder.remove();
        }
    }
}
